package com.googlecode.framework.orm.hibernate.criterion;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.sql.JoinType;
import org.hibernate.transform.ResultTransformer;
import org.springframework.util.ObjectUtils;

public class SafeDetachedCriteria extends DetachedCriteria {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -6443541283072181179L;

    /*
     * 需要初始化的属性
     */
    private Set<String> initProperties = new HashSet<String>();
    
    protected SafeDetachedCriteria(String entityName) {
        super(entityName);
    }

    protected SafeDetachedCriteria(String entityName, String alias) {
        super(entityName, alias);
    }

    protected SafeDetachedCriteria(CriteriaImpl impl, Criteria criteria) {
        super(impl, criteria);
    }
    
    public static SafeDetachedCriteria forEntityName(String entityName) {
        return new SafeDetachedCriteria(entityName);
    }
    
    public static SafeDetachedCriteria forEntityName(String entityName, String alias) {
        return new SafeDetachedCriteria(entityName, alias);
    }
    
    public static SafeDetachedCriteria forClass(Class<?> clazz) {
        return new SafeDetachedCriteria(clazz.getName());
    }
    
    public static SafeDetachedCriteria forClass(Class<?> clazz, String alias) {
        return new SafeDetachedCriteria(clazz.getName(), alias);
    }
    
    // --- 超级无敌分割线 ------------------------------------------------------------
    @Override
    public SafeDetachedCriteria add(Criterion criterion) {
        if (criterion != null) {
            super.add(criterion);
        }
        return this;
    }
    
    public SafeDetachedCriteria add(Criterion... criterions) {
        if (!ObjectUtils.isEmpty(criterions)) {
            for (Criterion criterion : criterions) {
                this.add(criterion);
            }
        }
        return this;
    }

    @Override
    public SafeDetachedCriteria addOrder(Order order) {
        if (order != null) {
            super.addOrder(order);    
        }
        return this;
    }
    
    /**
     * 添加多个排序
     * 
     * @param orders
     * @return
     */
    public SafeDetachedCriteria addOrders(Order... orders) {
        if (!ObjectUtils.isEmpty(orders)) {
            for (Order order : orders) {
                this.addOrder(order);
            }
        }
        return this;
    }
    
    @Override
    public SafeDetachedCriteria createCriteria(String associationPath, String alias) throws HibernateException {
        // FIXME 
        super.createCriteria(associationPath, alias);
        return this;
    }

    @Override
    public SafeDetachedCriteria createCriteria(String associationPath) throws HibernateException {
        // FIXME
        super.createCriteria(associationPath);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria createCriteria(String associationPath, JoinType joinType) throws HibernateException {
        // FIXME
        super.createCriteria(associationPath, joinType);
        return this;
    }

    @Override
    public SafeDetachedCriteria createCriteria(String associationPath, String alias, JoinType joinType) throws HibernateException {
        // FIXME
        super.createCriteria(associationPath, alias, joinType);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria createCriteria(String associationPath, String alias, JoinType joinType, Criterion withClause) throws HibernateException {
        // FIXME
        super.createCriteria(associationPath, alias, joinType, withClause);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria createAlias(String associationPath, String alias) throws HibernateException {
        super.createAlias(associationPath, alias);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria createAlias(String associationPath, String alias, JoinType joinType) throws HibernateException {
        super.createAlias(associationPath, alias, joinType);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria createAlias(String associationPath, String alias, JoinType joinType, Criterion withClause) throws HibernateException {
        super.createAlias(associationPath, alias, joinType, withClause);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria setFetchMode(String associationPath, FetchMode mode) throws HibernateException {
        super.setFetchMode(associationPath, mode);
        return this;
    }

    @Override
    public SafeDetachedCriteria setProjection(Projection projection) {
        super.setProjection(projection);
        return this;
    }
    
    /**
     * 添加多个投影
     * 
     * @param projections
     * @return
     */
    public SafeDetachedCriteria setProjections(Projection... projections) {
        if (!ObjectUtils.isEmpty(projections)) {
            ProjectionList projectionList = Projections.projectionList();
            for (Projection p : projections) {
                projectionList.add(p);
            }
            super.setProjection(projectionList);
        }
        return this;
    }


    @Override
    public SafeDetachedCriteria setResultTransformer(ResultTransformer resultTransformer) {
        super.setResultTransformer(resultTransformer);
        return this;
    }
    
    @Override
    public SafeDetachedCriteria setComment(String comment) {
        super.setComment(comment);
        return this;
    }

    @Override
    public DetachedCriteria setLockMode(LockMode lockMode) {
        super.setLockMode(lockMode);
        return this;
    }

    @Override
    public SafeDetachedCriteria setLockMode(String alias, LockMode lockMode) {
        super.setLockMode(alias, lockMode);
        return this;
    }
    
    public SafeDetachedCriteria asc(String propertyName) {
        addOrder(Order.asc(propertyName));
        return this;
    }

    public SafeDetachedCriteria desc(String propertyName) {
        addOrder(Order.desc(propertyName));
        return this;
    }
    
    /**
     * 添加需要初始化的属性
     * 
     * @param propertyName
     * @return
     */
    public SafeDetachedCriteria addInitProperty(String propertyName) {
        initProperties.add(propertyName);
        return this;
    }

    /**
     * 添加需要初始化的属性
     * 
     * @param propertyNames
     * @return
     */
    public SafeDetachedCriteria addInitProperties(String... propertyNames) {
        if (!ObjectUtils.isEmpty(propertyNames)) {
            for (String propertyName : propertyNames) {
                initProperties.add(propertyName);
            }
        }
        return this;
    }

    /**
     * 取得需要初始化的属性
     * 
     * @return
     */
    public String[] getInitProperties() {
        return initProperties.toArray(new String[initProperties.size()]);
    }
}
